package com.xhs.service.impl;

import com.alibaba.fastjson.JSON;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xhs.bo.LoginCodeBo;
import com.xhs.bo.UserBo;
import com.xhs.bo.UserFindBo;
import com.xhs.config.RedisKeyConfig;
import com.xhs.dao.UserDao;
import com.xhs.dao.UserDatilDao;
import com.xhs.dao.UserLogDao;
import com.xhs.entity.User;
import com.xhs.entity.UserDatil;
import com.xhs.entity.UserLog;
import com.xhs.service.intf.UserService;
import com.xhs.utils.*;
import com.xhs.vo.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;


@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao dao;

    @Autowired
    private UserLogDao logDao;

    @Autowired
    private UserDatilDao userDatilDao;

    @Value("${cs.pass.prikey}")
    private String priKey;


    //注册接口
    @Transactional
    @Override
    public R register(UserBo bo, String ip) {
        //1.判断是否为空
        if (bo != null) {
            //2.判断参数是否正确
            if (StringUtil.isNotEmpty(bo.getPassword()) && StringUtil.regexPhone(bo.getPhone())) {
                //3.校验是否校验过验证码
                if (JedisUtil.checkSet(RedisKeyConfig.REGISTER_PHONES, bo.getPhone())) {
                    //4.校验手机号是否存在
                    if (dao.selectOne(new QueryWrapper<User>().eq("phone", bo.getPhone())) == null) {
                        //5.把bo中的属性复制到user中
                        User user = BeanUtil.copyProperty(User.class, bo, bo.getClass().getDeclaredFields());
                        //6.为状态赋值
                        user.setFlag(SystemConfig.USER_FLAG_OK);
                        //7.设置密码（因为需要加密，所以之前虽然已经进行过了属性复制，但是密码需要重新赋值）
                        user.setPassword(EncryptUtil.rsaEnc(priKey, user.getPassword()));
                        //8.把user对象添加到数据库中
                        if (dao.insert(user) > 0) {
                            //9.把这个注册的行为记录到数据库中
                            logDao.insert(new UserLog(user.getId(), SystemConfig.USER_OP_ADD, "注册用户", ip, new Date()));
                            //10.把用户信息录入用户详情表
                            userDatilDao.insert(new UserDatil(user.getId(),1,new Date()));
                            return RUtil.ok(null);
                        }
                    }
                }
            }
        }
        return RUtil.fail();
    }

    //验证手机号是否存在
    @Override
    public R checkPhone(String phone) {
        //1.验证手机号格式是否正确
        if (StringUtil.regexPhone(phone)) {
            //2.通过手机号查询得到user对象
            User user = dao.selectOne(new QueryWrapper<User>().eq("phone", phone));
            //3.如果==null，证明手机号未注册
            if (user == null) {
                //4.返回OK
                return RUtil.ok(null);
            }

        }
        return RUtil.fail("手机号码已存在");
    }

    //账号密码登陆
    @Override
    public R loginByPassword(UserBo bo, String ip) {
        //1.判断bo是否有内容
        if (bo != null) {
            //2.判断bo中的属性是否合规
            if (StringUtil.isNotEmpty(bo.getPassword()) && StringUtil.regexPhone(bo.getPhone())) {
                //3.通过手机号查询得到一个user对象
                User user = dao.selectOne(new QueryWrapper<User>().eq("phone", bo.getPhone()));
                //4.如果有这个对象证明已经注册过了
                if (user != null) {
                    //5.判断这个账号的状态是否可用
                    if (user.getFlag() == SystemConfig.USER_FLAG_OK) {
                        //6.判断密码是否正确（将传进来的密码转换为密文）
                        if (user.getPassword().equals(EncryptUtil.rsaEnc(priKey, bo.getPassword()))) {
                            //7.查看是否已经登陆,已登陆账号禁止登陆（使用第10步存储的数据）
                            if (!JedisUtil.checkKey(RedisKeyConfig.REGISTER_PHONES + bo.getPhone())) {
                                //8.生成令牌，根据user的id属性
                                String token = JwtUtils.createToken(user.getId() + "");
                                //9.向jedis中存储用户信息，设置存活时常，key为自定义常量+令牌
                                JedisUtil.addStr(RedisKeyConfig.LOGIN_TOKEN + token, JSON.toJSONString(user), RedisKeyConfig.LOGIN_TOKEN_TIME);
                                //10.向jedis中存储令牌信息，key为自定义常量+用户手机号。（用于第7步判断是否已经登陆）
                                JedisUtil.addStr(RedisKeyConfig.LOGIN_PHONE + bo.getPhone(), token, RedisKeyConfig.LOGIN_TOKEN_TIME);
                                //11.添加用户操作日志
                                logDao.insert(new UserLog(user.getId(), SystemConfig.USER_OP_LOGIN, "登录成功", ip, new Date()));
                                return RUtil.ok(token);
                            }
                            return RUtil.fail("账号已登陆");
                        }
                    }
                }
            }
        }
        return RUtil.fail("账号或密码错误");
    }

    //手机号验证码登陆
    @Override
    @Transactional
    public R loginCode(LoginCodeBo bo, String ip) {
        //1.判断bo是否为空
        if (bo!=null){
            //2.验证手机号
            if (StringUtil.regexPhone(bo.getPhone())){
                String phoneKey = RedisKeyConfig.SMS_LCODE+bo.getPhone();
                //3.查询是否已经发送验证码
                if (JedisUtil.checkKey(phoneKey)){
                    //4.对比验证码是否正确
                    if (bo.getCode()==Integer.parseInt(JedisUtil.getStr(phoneKey))){
                        //5.查看是否已经登录（唯一登录）
                        if (!JedisUtil.checkKey(RedisKeyConfig.LOGIN_PHONE+bo.getPhone())){
                            //6查询登录用户信息
                            User user = dao.selectOne(new QueryWrapper<User>().eq("phone", bo.getPhone()));
                            //7.如果为null表示未注册
                            if (user==null){
                                user = new User();
                                user.setPhone(bo.getPhone());
                                user.setFlag(SystemConfig.USER_FLAG_OK);
                                user.setPassword(EncryptUtil.rsaEnc(priKey,bo.getCode()+""));
                                //8.自动注册
                                dao.insert(user);
                                //9.记录注册日志
                                logDao.insert(new UserLog(user.getId(),SystemConfig.USER_OP_ADD,"登录并注册",ip,new Date()));
                            }
                            //10.生成令牌，根据user的id属性
                            String token = JwtUtils.createToken(user.getId() + "");
                            //11.向jedis中存储用户信息，设置存活时常，key为自定义常量+令牌
                            JedisUtil.addStr(RedisKeyConfig.LOGIN_TOKEN + token, JSON.toJSONString(user), RedisKeyConfig.LOGIN_TOKEN_TIME);
                            //12.向jedis中存储令牌信息，key为自定义常量+用户手机号。（用于第7步判断是否已经登陆）
                            JedisUtil.addStr(RedisKeyConfig.LOGIN_PHONE + bo.getPhone(), token, RedisKeyConfig.LOGIN_TOKEN_TIME);
                            //13.添加用户操作日志
                            logDao.insert(new UserLog(user.getId(), SystemConfig.USER_OP_LOGIN, "登录成功", ip, new Date()));
                            JedisUtil.delKey(phoneKey);
                            return RUtil.ok(token);
                        }
                        return RUtil.fail("已在线");
                    }
                }
            }
        }
        return RUtil.fail("账号或验证码错误");
    }


    //验证找回验证码
    @Override
    public R checkFindCode(UserFindBo bo, String ip) {
        //1.判断bo是否为空
        if (bo!=null){
            //2.验证手机格式
            if (StringUtil.regexPhone(bo.getPhone())){
                String key = RedisKeyConfig.SMS_FCODE+bo.getPhone();
                //3.验证是否发送找回验证码
                if (JedisUtil.checkKey(key)){
                    //4.判断找回验证码是否正确
                    if (bo.getCode()==Integer.parseInt(JedisUtil.getStr(key))){
                        //5.验证码正确以后删除验证码
                        JedisUtil.delKey(key);
                        //6.将手机号添加到已验证队列中
                        JedisUtil.addSet(RedisKeyConfig.FIND_PHONES,bo.getPhone());
                        return RUtil.ok("验证码正确",null);
                    }
                }
            }
        }
        return RUtil.fail("验证码错误");
    }

    //在验证码通过后，修改密码
    @Override
    public R updatePassword(UserBo bo, String ip) {
        //1.判断bo是否为空
        if (bo!=null){
            //2.判断属性
            if (StringUtil.isNotEmpty(bo.getPassword())&&StringUtil.regexPhone(bo.getPhone())){
                String key = RedisKeyConfig.FIND_PHONES;
                //3.判断手机号是否已经校验过验证码
                if (JedisUtil.checkSet(key,bo.getPhone())){
                    //4.如果通过验证修改验证码
                    dao.updatePass(EncryptUtil.rsaEnc(priKey,bo.getPassword()), bo.getPhone());
                    //5.获取user对象（就是为了拿到id属性，添加日志）
                    User user = dao.selectOne(new QueryWrapper<User>().eq("phone", bo.getPhone()));
                    //6.添加操作日志
                    logDao.insert(new UserLog(user.getId(),SystemConfig.USER_OP_FIND,"密码找回成功",ip,new Date()));
                    String phoneKey = RedisKeyConfig.LOGIN_PHONE+bo.getPhone();
                    //7.判断是否已经登录
                    if(JedisUtil.checkKey(phoneKey)){
                        //8.删除用户信息
                        JedisUtil.delKey(RedisKeyConfig.LOGIN_TOKEN+JedisUtil.getStr(phoneKey));
                        //9.删除删除token
                        JedisUtil.delKey(phoneKey);
                    }
                    return RUtil.ok("密码找回成功",null);
                }
            }
        }
        return RUtil.fail("密码找回失败");
    }

    //校验token
    @Override
    public R checkToken(String token) {
        //1.判断token是否为空
        if (StringUtil.isNotEmpty(token)){
            //2.校验token是否存在（key为自定义字符+token，value为user信息）
            if (JedisUtil.checkKey(RedisKeyConfig.LOGIN_TOKEN+token)){
                return RUtil.ok("令牌有效",null);
            }
        }

        return RUtil.fail("令牌失效");
    }


    //删除令牌
    @Override
    public R deleToken(String token) {
        //1.判断token是否为空
        if (StringUtil.isNotEmpty(token)){
            String tokenKey = RedisKeyConfig.LOGIN_TOKEN+token;
            //2.验证token是否存在
            if (JedisUtil.checkKey(tokenKey)){
                User user = JSON.parseObject(JedisUtil.getStr(tokenKey), User.class);
                //3.删除存储token的set
                JedisUtil.delKey(RedisKeyConfig.LOGIN_PHONE+user.getPhone());
                //4.删除存储用户信息的set
                JedisUtil.delKey(tokenKey);
                return RUtil.ok("注销成功",null);
            }
        }
        return RUtil.fail("注销失败");
    }

    //通过token查询用户信息
    @Override
    public R queryUser(String token) {
        //1.判断是否为空
        if (StringUtil.isNotEmpty(token)){
            //2.查看token是否存在（这个Key的velue值是用户信息）
            if (JedisUtil.checkKey(RedisKeyConfig.LOGIN_TOKEN+token)){
                //3.获取user
                User user = JSON.parseObject(JedisUtil.getStr(RedisKeyConfig.LOGIN_TOKEN + token), User.class);
                //4.将密码对外隐藏
                user.setPassword("");
                return RUtil.ok(user);
            }
        }
        return RUtil.fail("获取失败");
    }
}
